/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2008-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#include "cnome_config.h"

#include <exception>
#include <iostream>
#include <list>
#include <sstream>
#include <stdio.h>
#include <string>

#include <boost/shared_ptr.hpp>
#include <boost/spirit/home/classic/error_handling.hpp>
#include <boost/spirit/home/classic/dynamic.hpp>

#include "util.h"

#include "actions.h"
#include "iterator.h"
#include "typedefs.h"
#include "directive_lookahead.h"
#include "scopes.h"
#include "symbol.h"
#include "tokens.h"
#include "variables.h"

namespace cnome { namespace util {
using namespace actions;
using namespace boost::wave;
using namespace scopes;
using namespace std;

sglUtil* sglUtil::m_instance=0; 

const char* getSuffixForSymbol(const symbol& smb) {
    switch(smb) {
        case T_IDENTIFIER:
                switch(smb.get_identifier_type()) {
                    case symbol::T_CLASS_NAME:
                    case symbol::T_ENUM_NAME:
                    case symbol::T_TEMPLATE_NAME:
                    case symbol::T_ORIGINAL_NAMESPACE_NAME:
                    case symbol::T_NAMESPACE_ALIAS:
                        return "::";
                        break;
                    default: // It must be a method
                        return "$";
                        break;
                    }
                break;
            case T_FIRST_TOKEN:
                return "::";
                break;
            case T_OPERATOR:
                return "$";
                break;
            default:
                return "";
                break;
        }
}

void appendAdorners(string& val, const adornersT& adrns, size_t& suffixSize) {
    for (adornersT::const_iterator it = adrns.begin(); it != adrns.end(); it++) {
        if (*it == T_CONST) {
            if (val.size() && (isalnum(val[val.size()-1]) || val[val.size() - 1] == '_')) {
                val += " ";
                suffixSize++;
            }
        
            val += it->get_value().c_str();
            suffixSize += it->get_value().size();
        }
    }
}

void appendAdorners(string& val, const adornersT& adrs) {
    size_t suffixSize = 0;
    appendAdorners(val, adrs, suffixSize);
}

std::string& sblToStr(const iterator& first, const iterator& last, string& val) {
    bool isPrevOperator = false;
    int tmplLevel = -1;
    for (iterator it=first;it!=last;it++) {
        if (*it == T_LESS) {
            ++tmplLevel;
        }
        else if (*it == T_GREATER) {
            --tmplLevel;
        }
        else if (tmplLevel == -1) {
            val += it->get_value().c_str();
            if (isPrevOperator && *it==T_IDENTIFIER)
                val += " ";
            isPrevOperator = *it == T_OPERATOR;
        }
    }
    return val;
}

// TODO: Study the use of restart parameter bellow. ALB 
std::string& sblToStr(scopeT& sbl, std::string& scp, bool restart) {
    static const symbol* prevTk(&smb_FIRST_TOKEN);
    static std::string aux;
    if (restart||scp.size()==0) {
        aux = getSuffixForSymbol(smb_FIRST_TOKEN);
    }
    bool noMore = false;
    for (scopeT::iterator it = sbl.begin(); it != sbl.end(); it++) {
        symbol* tkaux = it->get();
        if (noMore) {
            std::cerr << "sblToStr: noMore " << std::endl;
            // TODO: Create a cnome_exception derived from spirit::classic::exception. ALB 
           // throw std::exception("Internal compiler error.");
            throw std::exception();
        }
        if (*tkaux != T_TYPEDEF) {
            scp += aux + tkaux->get_value().c_str();
        }
        itSymbolItem its;
        itSymbolItem itAux;
        switch(*tkaux) {
            case T_TYPEDEF:
                break;
            case T_CHAR:
            case T_WCHART:
            case T_BOOL:
            case T_SHORT:
            case T_INT:
            case T_LONG:
            case T_SIGNED:
            case T_UNSIGNED:
            case T_FLOAT:
            case T_DOUBLE:
            case T_VOID:
                scp = tkaux->get_value().c_str();
                break;
            case T_IDENTIFIER:
                switch(*prevTk) {
                    case T_CHAR: case T_WCHART:    case T_BOOL: case T_SHORT: case T_INT: case T_LONG: 
                    case T_SIGNED: case T_UNSIGNED: case T_FLOAT: case T_DOUBLE: case T_VOID:
                        scp = ("::" + tkaux->get_value()).c_str();
                        break;
		    default:
		        break;
                }

                if ( ((itAux = cnome_symbols.find(scp)) != cnome_symbols.end()) &&
                    (itAux->second->get_identifier_type() != symbol::NONE)) {
                     tkaux->set_identifier_type(itAux->second->get_identifier_type());
                     (*it)->set_identifier_type(itAux->second->get_identifier_type()); // Update internal scope data 
                }                                                              // TODO: Redesign the class to avoid the uggly solution above
                switch(tkaux->get_identifier_type()) {
                    case symbol::T_CLASS_NAME:
                    case symbol::T_ENUM_NAME:
                    case symbol::T_TEMPLATE_NAME:
                        aux = getSuffixForSymbol(*tkaux);
                        break;
                    case symbol::T_ORIGINAL_NAMESPACE_NAME:
                    case symbol::T_NAMESPACE_ALIAS:
                        if (   prevTk->get_identifier_type() == symbol::T_CLASS_NAME || prevTk->get_identifier_type() == symbol::T_ENUM_NAME
                            || prevTk->get_identifier_type() == symbol::T_TEMPLATE_NAME)
                            scp = ("::"+tkaux->get_value()).c_str();
                        if ((its = cnome_symbols.find(scp)) != cnome_symbols.end())
                            if (its->second->get_identifier_type()==symbol::T_NAMESPACE_ALIAS&&its->second->get_type_symbol()) // Translate scope
                                scp = its->second->get_type_symbol()->to_str();
                        aux = getSuffixForSymbol(*tkaux);
                        break;
                    default:
                        aux = getSuffixForSymbol(*tkaux);;
                        break;
                }
                break;
            default:
                aux = getSuffixForSymbol(*tkaux);
                break;
        }
        appendAdorners(scp, tkaux->get_adorners());
        prevTk = tkaux;
    }
    return scp;

}

const symbolPtr& GetMthToken() {
    return var::mthScope;
}

sblAttribute operator|(sblAttribute a, sblAttribute b) { return static_cast<sblAttribute>(static_cast<unsigned int>(a)|static_cast<unsigned int>(b)); }

sblAttribute mmbSblToStr(iterator& first, const iterator& last, string& val, string& strAux, adornersT& adrns) {
    bool isArray = false;
    bool isPtrToFct = false; // Is pointer to function?
    bool isInPtrToFctDcl = false;
    bool foundOperator = false;
    bool foundOperatorCvs = false;
    bool found1stId = false;
    bool foundStarInPtrToFctDcl = false;
    bool searchForTypePrm = true;
    bool isMethod = false;
    bool haveAlreadySeeLP = false;
    adornersT auxAdrns;
    adornersT opAdrns; // TODO: Verify if auxAdrns is enough to handle all situation
    bool noMoreOpAdrns = false;
    iterator auxIt(last);
    iterator itP(last);
    for (iterator it=first;it!=last;it++) {
        switch(*it) {
            case T_AND:
                if (!foundOperator || haveAlreadySeeLP)
                    adrns.push_back(*it);
                else {
                    while (opAdrns.size()) {  // Get the const declarations
                        if (val.size() && isalnum(val[val.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                            val += ' ';
                        val += opAdrns.back();
                        opAdrns.pop_back();
                    }
                    val += it->get_value().c_str();
                }
                break;
            case T_CONST:
                if (!foundOperator || noMoreOpAdrns)
                    adrns.push_back(*it);
                else
                    opAdrns.push_back(*it);
                break;
            case T_STAR:
                if (!foundOperator || haveAlreadySeeLP)
                    adrns.push_back(*it);
                else {
                    while (opAdrns.size()) {  // Get the const declarations
                        if (val.size() && isalnum(val[val.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                            val += ' ';
                        val += opAdrns.back();
                        opAdrns.pop_back();
                    }
                    val += it->get_value().c_str();
                }
                if (isInPtrToFctDcl)
                    foundStarInPtrToFctDcl = true;
                break;
            case T_LEFTBRACKET:
                strAux += it->get_value().c_str();
                isArray = true;
                break;
            case T_RIGHTBRACKET:
                strAux += it->get_value().c_str();
                adrns.push_back(*it);
                isArray = false;
                strAux = "";
                break;
            case T_LEFTPAREN:
                if (!found1stId) {
                    if (!foundOperator) {
                        isPtrToFct = true;
                        isInPtrToFctDcl = true;
                    }
                    else {
                        while (opAdrns.size()) {  // Get the const declarations
                            if (val.size() && isalnum(val[val.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                                val += ' ';
                            val += opAdrns.back();
                            opAdrns.pop_back();
                        }
                        noMoreOpAdrns = true;
                    }
                }
                else {
                    isMethod = !isPtrToFct;
                    searchForTypePrm = true;  // TODO: Verify if it is possible to have a "int f(a b,int (*)(void))"
                }
                adrns.push_back(*it);
                haveAlreadySeeLP = true;
                break;
            case T_RIGHTPAREN:
                if (isInPtrToFctDcl) {
                    isInPtrToFctDcl = false;
                    if (foundStarInPtrToFctDcl)
                        for (adornersT::const_iterator ita = auxAdrns.begin(); ita != auxAdrns.end(); ita++)
                            adrns.push_back(*ita);
                    else {
                        for (adornersT::const_iterator ita = auxAdrns.begin(); ita != auxAdrns.end(); ita++)
                            val += *ita;
                        first = auxIt;
                        found1stId = true;
                    }
                    auxAdrns.clear();
                }
                else if (adrns.back() == T_LEFTPAREN) // Is last token == left parentesis
                    adrns.push_back(token_t(T_VOID, "void", adrns.back().get_position()));  // If so, add void to adrns. 
                // TODO: Study if a situation like int (*a)(b()) could ocurrs and if so handle better it.

                adrns.push_back(*it);
                break;
            case T_COMMA:
                adrns.push_back(*it);
                searchForTypePrm = true;
                break;
            case T_OPERATOR:
                val += (it->get_value() + " ").c_str();
                isMethod = true;
                foundOperator = true;
                break;
            case T_IDENTIFIER:
                if (itP != last && *itP == T_OPERATOR) {
                    foundOperator = false;
                    foundOperatorCvs = true;
                }
                if (found1stId) {
                    if (!isPtrToFct)
                        strAux += it->get_value().c_str();
                    else if (searchForTypePrm) {
                        searchForTypePrm = false;
                        adrns.push_back(*it);
                    }
                }
                else {
                    if (isInPtrToFctDcl&&!foundStarInPtrToFctDcl) {
                        auxAdrns.push_back(*it);
                        if (auxIt == last)
                            auxIt = it;
                    }
                    else {
                        if (val.size() && isalnum(val[val.size()-1]))
                            val += ' ';
                        val += it->get_value().c_str();
                        first = it;
                        found1stId = true;
                    }
                }
                break;
            default:  // TODO: Verify if this situation is handled correctly
                if (found1stId) {
                    if (isPtrToFct)
                        adrns.push_back(*it);
                    else 
                        strAux += it->get_value().c_str();
                }
                else {
                    if (isInPtrToFctDcl)
                        auxAdrns.push_back(*it);
                    else {
                        if (val.size() && isalnum(val[val.size()-1]) && isalnum(it->get_value()[0]))
                            val += ' ';
                        val += it->get_value().c_str();
                    }
                }
                break;
        }
        itP = it;
    }
    return   (isArray?Array:None)
           | (isPtrToFct?PtrToFct:None)
           | (isMethod?Method:None)
           | (foundOperator?Operator:None)
           | (foundOperatorCvs?OperatorCvs:None);
}

sblAttribute mtdSblToStr(iterator& first, const iterator& last, string& val, string& mthName, adornersT& adrns) {
    bool isTypeDefDcl = var::typeDecl.size()&&*var::typeDecl.front()==T_TYPEDEF;
    bool afterFirstId = false;
    bool justAftertFirstLP = false;
    bool haveAlreadySeeLP = false;
    bool isMethodConst = false;
    bool foundOperator = false;
    bool foundOperatorCvs = false;
	bool isGettingPtfName = false;
    std::string auxScp;
    int insideParameters = 0;
    adornersT opAdrns;
    for (iterator itv=first,itvP=last;itv!=last;itv++) {
        itSymbolItem it;
        auxScp="";
        symbol tk(*itv, symbol::other, itv.get_cnome_position());
        if (!haveAlreadySeeLP)
            switch(tk) {
                case T_AND:
                case T_STAR:
					if (isGettingPtfName && tk == T_STAR) {
						mthName += '*';
					}
                    else if (!foundOperator)
                        adrns.push_back(*itv);
                    else {
                        while (opAdrns.size()) {  // Get the const declarations
                            if (val.size() && isalnum(val[val.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                                val += ' ';
                            if (mthName.size() && isalnum(mthName[mthName.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                                mthName += ' ';
                            val += opAdrns.back();
                            mthName += opAdrns.back();
                            opAdrns.pop_back();
                        }
                        mthName += itv->get_value().c_str();
                    }
                    break;
                case T_CONST:
                    if (!afterFirstId) {
                        if (!foundOperator)
                            adrns.push_back(*itv);
                        else
                            opAdrns.push_back(*itv);
                    }
                    else
                        if (!insideParameters)
                            isMethodConst = true;
                    break;
                case T_OPERATOR:
                    mthName += (tk.get_value() + " ").c_str();
                    foundOperator = true;
                    break;
                case T_LEFTPAREN:
                    if (foundOperator)
                        while (opAdrns.size()) {  // Get the const declarations
                            if (val.size() && isalnum(val[val.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                                val += ' ';
                            if (mthName.size() && isalnum(mthName[mthName.size()-1]) && isalnum(opAdrns.back().get_value()[0]))
                                mthName += ' ';
                            val += opAdrns.back();
                            mthName += opAdrns.back();
                            opAdrns.pop_back();
                        }
                    break;
                case T_IDENTIFIER:
                    if (itvP != last && *itvP == T_OPERATOR) {
                        foundOperator = false;
                        foundOperatorCvs = true;
                    }
                    mthName += tk.get_value().c_str();
                    break;
                default:
                    mthName += tk.get_value().c_str();
                    break;
            }
        else {  // TODO: Types and parameter need to be handled differently.
            switch(tk) {
                case T_IDENTIFIER:
                    {
                        get_scope(auxScp, tk.get_value().c_str());
                        scopesFromStr scopes(auxScp, tk.get_value().size());
                        while (scopes.next_scope().size()) {
                             if ((it = cnome_symbols.find(scopes.current_scope())) != cnome_symbols.end()) {
                                  tk.set_identifier_type(it->second->get_identifier_type());
#if defined(CNOME_DEBUG)
                                  std::cout << "mtdSblToStr: scopes.current_scope() = " << scopes.current_scope() << endl;
                                  std::cout << "mtdSblToStr: curScp = " << val << endl;
#endif
                                  break;
                             }
                        }
                    }
                    break;
                case T_AND:
                case T_STAR:
                    auxScp += tk.get_value().c_str();
                    break;
                case T_CONST:
                    if (!afterFirstId)
                        auxScp += tk.get_value().c_str();
                    else
                        if (!insideParameters)
                            isMethodConst = true;
                    break;
                default:
		    break;
            }
            switch(tk.get_identifier_type()) {
                case symbol::T_CLASS_NAME:
                case symbol::T_ENUM_NAME:
                case symbol::T_TYPEDEF_NAME:
                case symbol::T_NAMESPACE_ALIAS:
                case symbol::T_ORIGINAL_NAMESPACE_NAME:
                case symbol::T_TEMPLATE_NAME:
                    get_scope(auxScp);
                    auxScp = "::";
                    auxScp = auxScp + mthName + "$" + tk.get_value().c_str();
                    if ((it = cnome_symbols.find(auxScp)) != cnome_symbols.end())
                        tk.set_identifier_type(it->second->get_identifier_type());
                    break;
                default:
		    break;
            }
        }

        if (tk == T_RIGHTPAREN) {
            insideParameters--;
            if (justAftertFirstLP)
                val += "void";
        }
        if (    (tk != T_CONST)
             && (    !afterFirstId 
                  || (    tk != T_IDENTIFIER 
                       || tk.get_identifier_type() == symbol::T_TEMPLATE_NAME 
                       || tk.get_identifier_type() == symbol::T_CLASS_NAME 
                       || tk.get_identifier_type() == symbol::T_ENUM_NAME 
                       || tk.get_identifier_type() == symbol::T_TYPEDEF_NAME) 
                )
           ) {  // The name of parameter doesn't correspond to assign of method
 
            if (val.size() && isalnum(val[val.size()-1]) && isalnum(tk.get_value()[0]))
                val += ' ';
            val += tk.get_value().c_str();
        }
        if ( !afterFirstId && (    tk == T_IDENTIFIER && (tk.get_identifier_type() == symbol::NONE || tk.get_identifier_type() == symbol::T_CLASS_NAME
                                || tk.get_identifier_type() == symbol::T_TEMPLATE_NAME) ) )
            afterFirstId = true;
        if (afterFirstId && tk == T_COLON_COLON)
            afterFirstId = false;
        // Internally a() is know as a(void)
        if (haveAlreadySeeLP) {
            if (tk != T_LEFTPAREN)
                justAftertFirstLP = false;
            else
                insideParameters++;
        }
        else
            if (tk == T_LEFTPAREN) {
				if (mthName.size() > 0) {
					insideParameters++;
					if (!justAftertFirstLP) {
						justAftertFirstLP = true;
						haveAlreadySeeLP = true;
						size_t idx = mthName.rfind('(');
						if (idx == mthName.size()-1) 
							mthName = mthName.substr(0,idx);
					}
				}
				else {
					mthName += '(';
					isGettingPtfName = true;
				}
            }
        itvP = itv;
    }
    return   (isTypeDefDcl?TypeDefDcl:None)
           | (isMethodConst?MethodConst:None)
           | (foundOperator?Operator:None)
           | (foundOperatorCvs?OperatorCvs:None);
}

string& sblToStr(iterator& first, const iterator& last, string& val, adornersT& adrns, size_t& suffixSize) {
    bool needScope = false;
    iterator lclF=first;
    iterator lclL=last;
    iterator prev=last;
    for(bool goOut=false,canGoOut=false;!goOut&&lclF!=lclL;lclF++) {
        switch(*lclF) {
            case T_AND:
            case T_STAR:
            case T_CONST:
                adrns.push_back(*lclF);
                break;
            case T_TYPEDEF:
                {
                // TODO: Handle typedef???
                symbolPtr tmp = symbolPtr(new symbol(*lclF, symbol::other, lclF.get_cnome_position()));
                var::typeDecl.push_back(tmp);
                }
                break;
            case T_SIGNED:
            case T_UNSIGNED:
                // TODO: Handle signed and unsigned keywords correctly
                val += lclF->get_value().c_str();
                first=lclF;
                canGoOut=true;
                break;
            case T_CHAR:
            case T_WCHART:
            case T_SHORT:
            case T_INT:
            case T_LONG:
                if (*prev == T_SIGNED || *prev == T_UNSIGNED || *prev == T_LONG || *prev == T_SHORT)
                    val += " ";
                val += lclF->get_value().c_str();
                first=lclF;
                canGoOut=true;
                break;
            case T_BOOL:
            case T_FLOAT:
            case T_VOID:
                val += lclF->get_value().c_str();
                first=lclF;
                canGoOut=true;
                break;
            case T_DOUBLE:
                if (*prev == T_LONG)
                    val += " ";
                val += lclF->get_value().c_str();
                first=lclF;
                canGoOut=true;
                break;
            case T_IDENTIFIER:
                val += lclF->get_value().c_str();
                needScope = true;
                first=lclF;
                canGoOut=true;
                break;
            case T_LESS:
            case T_GREATER:
            case T_COLON_COLON:
                // TODO: Verify if it will be necessary test "."
                val += lclF->get_value().c_str();
                break;
            case T_LEFTBRACE:
                goOut = true;
                break;
            case T_LEFTPAREN:
                if (canGoOut)
                    goOut=true;
                break;
            default:
                break;
        }
        prev = lclF;
    }
    suffixSize = val.size();

    std::string curScp;
    if (needScope) {
        get_scope(curScp,val.c_str());
        val = curScp;
    }
    return val;
}

string& sblToStr(iterator& first, const iterator& last, string& val, adornersT& adrns) {
    size_t suffixSize;
    return sblToStr(first, last, val, adrns, suffixSize);
}

size_t findLess(const string& val, size_t greaterIdx) {
    size_t auxgreaterIdx = greaterIdx;
    int insideParameter = 1;
    for (auxgreaterIdx = greaterIdx-1; auxgreaterIdx < val.size(); auxgreaterIdx--) {
        if (val[auxgreaterIdx] == '<')
            insideParameter--;
        else if (val[auxgreaterIdx] == '>')
            insideParameter++;
        if (!insideParameter)
            break;
    }
    return !insideParameter?auxgreaterIdx:string::npos;
}

// Find the type str as a template instatiation. if it doesn't 
// exist it will be declared.
itSymbolItem findTptTypeDecl(const string& str, iterator& first) {
    itSymbolItem it = cnome_symbols.end();
    bool cond1;
    if (    (cond1=(str.size() >= sizeof("a<>")-1 && str[str.size()-1] == '>'))
         || (str.size() >=sizeof("a<>const")-1 && str.substr(str.size()-(sizeof(">const")-1)) == ">const") ) {
        size_t lessIdx = findLess(str, str.size()-(cond1?1:5));
        if (lessIdx == string::npos || lessIdx == 0)
            return it;
        bool isTptImplicitInfered = false;
        string aux = str.substr(0, lessIdx);
        while (    (it = cnome_symbols.find_smallest(aux)) != cnome_symbols.end()
                && (    it->first.size() == aux.size()
                     || (    it->first.size() > aux.size() 
                          && it->first.substr(0,aux.size()) == aux 
                          && !isalnum(it->first[aux.size()]) && it->first[aux.size()]!='_'
                        )
                   )
                && !(isTptImplicitInfered=it->second->get_identifier_type()==symbol::T_TEMPLATE_NAME)
              ) { 
            it++;
        }
        if (!isTptImplicitInfered)
            return cnome_symbols.end();
        // Declare template instatiation
        size_t idx = str.find_last_of(":$", lessIdx); // Verify if will work for all situations
        if (idx >= str.size())
            idx = 0;
        else
            idx++;
        symbolPtr smb = symbolPtr(new symbol(token_t(T_IDENTIFIER, str.substr(idx).c_str(), first->get_position()), symbol::other, first.get_cnome_position()));
        smb->set_identifier_type(symbol::T_CLASS_NAME);
        smb->set_scope(get_symbol_scope(aux.c_str())!=cnome_symbols.end()?get_symbol_scope(aux.c_str())->second:symbolPtr(static_cast<symbol*>(0)));
        smb->set_symbol_status(symbol::defined);
        cnome_symbols[smb->to_str()] = smb;
        it = cnome_symbols.find(smb->to_str());
    }

    return it;
}

// Find the type str and if it is a const type implicity 
// declare it if it doesn't exist. Also, if it is a template
// instatiation declares it.
itSymbolItem findTypeDecl(const string& str, iterator& first) {
    itSymbolItem it;
    if ((it = cnome_symbols.find(str)) != cnome_symbols.end())
        return it;
    // Verify if str has "const" at the end
    if (str.size() > 5 && str.substr(str.size()-5) == "const") {
        bool whiteSpace = isspace(str[str.size()-6]) != 0;
        if ((it = cnome_symbols.find(str.substr(0, str.size()-(whiteSpace?6:5)))) != cnome_symbols.end()) {   // Implicity declare the const type
            symbolPtr smb = symbolPtr(new symbol(*it->second));
            smb->set_position(first->get_position());
            adornersT adrns;
            adrns.push_back(token_t(T_CONST, "const", first->get_position()));
            smb->set_adorners(adrns);
            cnome_symbols[str] = smb;
            it = cnome_symbols.find(str);
        }
        return it;
    }
    if ((it = findTptTypeDecl(str, first)) != cnome_symbols.end())
        return it;

    return cnome_symbols.end();
}

symbolPtr declPtrToFct(const string& strTypeDecl, iterator& first) {
    symbolPtr smb = symbolPtr(new symbol(token_t(T_IDENTIFIER,strTypeDecl.c_str(), first->get_position()), symbol::other, first.get_cnome_position()));
    // TODO: Set scope and other data
    smb->set_symbol_type(symbol::point_to_function);
    cnome_symbols[smb->to_str()] = smb;
    return smb;
}

void suffixMethodName(std::string& val, scopeT& tmplPrms, adornersT* adorners) {
    val = ""; // mthName;

    // Handle template parameters
    lvlConstItPrms begin=var::tmplPrms.begin(parameter_scope::current);
    lvlConstItPrms end = var::tmplPrms.end(parameter_scope::current);
    if (begin != end) {
        val += '<';
        adorners->push_back(token_t(T_LESS, "<", token_t::position_type()));
    }
    int pos;
    lvlConstItPrms its;
    for (its=begin,pos=0;its!=end;) {
        if (its->second.get_type()->get_annotation()->get_tag() == PARAMETERANNOTATION) {
           symbolPtr sybIt(dynamic_cast<parameter_annotation*>(its->second.get_type()->get_annotation().get())->get_symbol_item_ptr());
           val += sybIt->get_value().c_str();
           appendAdorners(val, sybIt->get_adorners());
        }

        symbolPtr symbIt2;
        if (its->second.get_var() && its->second.get_var()->get_annotation()) {
            if (its->second.get_var()->get_annotation()->get_tag() == PARAMETERANNOTATION && 
                (symbIt2 = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr())->get_parameter_position()==pos) {
                for (adornersT::const_iterator itaV = symbIt2->get_adorners().begin(); itaV != symbIt2->get_adorners().end(); itaV++)
                    val += itaV->get_value().c_str();
            }
            else if (its->second.get_var()->get_annotation()->get_tag() == PARENTHESISANNOTATION) {
                val += its->second.get_var()->get_value().c_str();
            }
        }

        ++pos;
        ++its;
        if (its!=end) {
            val +=',';
        }
        else
            break;
    }
    if (begin != end) {
        val += '>';
        adorners->push_back(token_t(T_GREATER, ">", token_t::position_type()));
    }

    // Handle method parameters
    val += '(';
    adorners->push_back(token_t(T_RIGHTPAREN, "(", token_t::position_type()));
    // Finish the method signature using the parameters
    begin = var::prms.begin(parameter_scope::next);
    end = var::prms.end(parameter_scope::next);
    for (its=begin,pos=0;its!=end;) {
        if (its->second.get_type()->get_annotation()->get_tag() == PARAMETERANNOTATION) {
            symbolPtr sybIt(dynamic_cast<parameter_annotation*>(its->second.get_type()->get_annotation().get())->get_symbol_item_ptr());
            val += sybIt->to_str();
            appendAdorners(val, sybIt->get_adorners());
        }

        symbolPtr symbIt2;
        if (its->second.get_var() && its->second.get_var()->get_annotation()) {
            if (its->second.get_var()->get_annotation()->get_tag() == PARAMETERANNOTATION && 
                (symbIt2 = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr())->get_parameter_position()==pos) {
                for (adornersT::const_iterator itaV = symbIt2->get_adorners().begin(); itaV != symbIt2->get_adorners().end(); itaV++)
                    val += itaV->get_value().c_str();
            }
            else if (its->second.get_var()->get_annotation()->get_tag() == PARENTHESISANNOTATION) {
                val += its->second.get_var()->get_value().c_str();
            }
        }

        ++pos;
        ++its;
        if (its!=end) {
            val +=',';
        }
        else
            break;
    }
    if (begin != end)
        val += ')';
    else
        val += "void)";
}

void suffixMethodName(std::string& val, scopeT& tmplPrms) {
    adornersT adorners;
    suffixMethodName(val, tmplPrms, &adorners);
}

void suffixMethodName(std::string& val) {
    scopeT tmplPrms;
    suffixMethodName(val, tmplPrms);
}

//void getOldPrms(std::string& str, prmsT& oldPrms) {
//    std::map<int, symbolPtr> auxPrms;
//    std::map<int, symbolPtr>::iterator itIntItem;
//    const char* pc1;
//    const char* pc2;
//    size_t sz;
//    bool r1, r2;
//
//    str += '$';
//
//    for (itSymbolItem it = cnome_symbols.find(str);
//         (r1 = it != cnome_symbols.end()) && !strncmp(pc1=it->second->to_str(), pc2=str.c_str(), sz=str.size());
//         it++)
//         if (r2 = it->second->get_symbol_type() == symbol::parameter)
//             auxPrms[it->second->get_parameter_position()] = it->second;
//
//    for (itIntItem = auxPrms.begin(); itIntItem != auxPrms.end(); itIntItem++)
//        oldPrms[dynamic_cast<parameter_annotation*>(itIntItem->second->get_annotation().get())->get_index()] = *itIntItem->second;
//}


itSymbolItem verifyMethodName(iterator& first, const string& curScope, bool& isDataMember, bool& reDeclaration) {
    reDeclaration = false;
    isDataMember = false;
    itSymbolItem it;
    if ((it=cnome_symbols.find(curScope)) != cnome_symbols.end()) {   // Method already considered declared. Try identify why.
        if ( it->second->get_position().get_file()==first->get_position().get_file() && 
             it->second->get_position().get_line()==first->get_position().get_line() && 
             it->second->get_position().get_column()==first->get_position().get_column()) {   // parser backtrack
            return it;
        }
        else if (it->second->get_symbol_type()==symbol::member) {  // Must change to method?   
            isDataMember = true;  
        }
        else if (    it->second->get_symbol_status()==symbol::declared
            || it->second->get_symbol_status()==symbol::defined ) {
            // TODO: Verify if var::prmVars.clear() must be called
            // return; // Another declaration
            reDeclaration = true;
        }
        else {   // Already declared
            static string msg = "";
            msg = msg + "Identifier '"+curScope+"' already declared.";

              std::cerr << std::endl << msg<< std::endl;
            std::cerr << (it->second->get_symbol_type()==symbol::member?"member": 
                         (it->second->get_symbol_type()==symbol::method)?"method":"other")
                      <<", "
                      << (it->second->get_symbol_status()==symbol::declared?"declared":
                         (it->second->get_symbol_status()==symbol::defined?"defined":"unknown"))
                      << std::endl;
            std::cerr 
                      << first->get_position().get_file() << "(" 
                      << first->get_position().get_line() << ','
                      << first->get_position().get_column() <<")"
                      << std::endl;

            boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
            
        }
    }
    return it;
}

bool isCtorDecl(const string& curScope) {
    std::string tmp1,tmp2;
    // Check for constructor declaration
    size_t idx = curScope.find_first_of("(");
    if (idx!=curScope.npos) {
        size_t idx2 = curScope.find_last_of(":",idx);
        if (idx2!=curScope.npos) {
            size_t idx3 = curScope.find_last_of(":",idx2<2?0:idx2-2);
            if (idx3!=curScope.npos) {
                int dec = 2;
                if (curScope[idx2+1] == '~') {
                    idx2++;
                    dec++;
                }
                bool ret = (tmp1=curScope.substr(idx2+1,idx-idx2-1))==
                       (tmp2=curScope.substr(idx3+1,idx2-idx3-dec));
                return ret;
            }
        }
    }
    return false;
}

bool isCtorDeclWithoutParent(const string& curScope) {
    // Verify special case of constructor and destructor
    // Consider that the curScope always start with "::" and end with isalnum or '_'
    // TODO: Analyze the comment above. Alb
    int idxI1, idxF1;
      int idxI2, idxF2;
      for (idxF1 = idxI1 = static_cast<int>(curScope.length())-1; idxI1 >= 0 && (isalnum(curScope[idxI1])||curScope[idxI1]=='_'); idxI1--);
       for (idxF2 = idxI1; idxF2 >= 0 && ispunct(curScope[idxF2]) && curScope[idxF2]!='_'; idxF2--);
      for (idxI2 = idxF2; idxI2 >= 0 && (isalnum(curScope[idxI2]) || curScope[idxI2]=='_'); idxI2--);
      if (idxF2!=-1) {
          std::string sc1(curScope.substr(idxI1+1,idxF1-idxI1));
          std::string sc2(curScope.substr(idxI2+1,idxF2-idxI2));
          if (sc1==sc2)
            return true;
    }
    return false;
}

void adjustPrmVars(symbolPtr& smb) {
    int pos;
    lvlItPrms its;
    lvlItPrms end = var::prms.end(parameter_scope::next);
    for (pos=0,its=var::prms.begin(parameter_scope::next);its!=end; ++its) {
        while (its!=end && its->second.get_type()->get_annotation()->get_tag() != PARAMETERANNOTATION )
            ++its;
        if (its == end)
            continue;

        symbolPtr sybIts = dynamic_cast<parameter_annotation*>(its->second.get_type()->get_annotation().get())->get_symbol_item_ptr();
        if (!its->second.get_var() || pos != dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr()->get_parameter_position()) {    // Implicitly add prmVar
            char auxStr[20];
            sprintf(auxStr,"%1d",pos);
            symbolPtr auxSmb = symbolPtr(new symbol(token_t(T_IDENTIFIER,auxStr, its->second.get_type()->get_position()), symbol::parameter, sybIts->get_cnome_position()));
            auxSmb->set_type_symbol(sybIts);
            auxSmb->set_annotation(token_annotation_ptrT(new parameter_annotation(auxSmb, auxSmb->get_identifier_type(), var::prms.get_pos().new_vectorX(pos))));
            const_cast<prm&>(its->second).set_var(*auxSmb); 
        }
        its->second.get_var()->set_token_id(T_IDENTIFIER);
        symbolPtr sybItv = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr();
        sybItv->set_symbol_type(symbol::parameter);
        sybItv->set_scope(cnome_symbols.find(smb->to_str())!=cnome_symbols.end()?cnome_symbols.find(smb->to_str())->second:symbolPtr(static_cast<symbol*>(0)));
        sybItv->set_parameter_position(pos);  // TODO (alb): Fix this.
        ++pos;
    }
}

void adjustTmplPrms(symbolPtr& smb) {
    itSymbolItem itSmb(cnome_symbols.find(smb->to_str()));
    symbolPtr itScp(itSmb!=cnome_symbols.end()?itSmb->second:symbolPtr(static_cast<symbol*>(0)));
    lvlItPrms its;
    lvlItPrms end = var::tmplPrms.end(parameter_scope::next);
    for (its=var::tmplPrms.begin(parameter_scope::next);its!= end; ++its) {
        if (!its->second.get_var()) {
            symbolPtr sybIts = dynamic_cast<parameter_annotation*>(its->second.get_type()->get_annotation().get())->get_symbol_item_ptr();
            if (cnome_symbols.find(sybIts->to_str())!=cnome_symbols.end()) {
                cnome_symbols.erase(sybIts->to_str());
            }
            sybIts->get_references().clear();
            sybIts->set_scope(itScp);
            cnome_symbols[sybIts->to_str()] = sybIts;
        }
        else {
            symbolPtr sybItv = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr();
            if (cnome_symbols.find(sybItv->to_str())!=cnome_symbols.end()) {
                cnome_symbols.erase(sybItv->to_str());
            }
            sybItv->get_references().clear();
            sybItv->set_scope(itScp);
            cnome_symbols[sybItv->to_str()] = sybItv;
        }
    }
}

void declareParameters(itSymbolItem& it) {
    for (itPrms its=var::prms.begin();its!=var::prms.end();++its) {
        if (!its->second.get_var()) {
            continue;
        }
        if (its->second.get_var()->get_annotation()->get_tag() != PARAMETERANNOTATION) {
            continue;
        }
        symbolPtr sybItv = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr();
        cnome_symbols[sybItv->to_str()] = symbolPtr(sybItv);          // Add parameter to symbol table 
        it->second->add(cnome_symbols.find(sybItv->to_str())->second);  // to method symbol 
                                                                  
#if defined(CNOME_DEBUG)
        std::cout << "newMethod: Parameter: " << dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr()->to_str() << std::endl;
#endif
    }
    var::prms.clearVars();  // Now clear all parameters
}

bool verifyCtorDecl(bool ctorDecl, symbolPtr& smb, iterator& first) {
    if (ctorDecl && smb->get_type_symbol()) {
#ifdef _DEBUG
        const char* pc1 = smb->to_str();
#endif
        static string msg = "";
        msg = msg + "Constructor '"+smb->to_str()+"' returning a value.";

        std::cerr << std::endl << msg<< std::endl;
        std::cerr 
                  << first->get_position().get_file() << "(" 
                  << first->get_position().get_line() << ','
                  << first->get_position().get_column() <<")"
                  << std::endl;

        boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
    }
    return true;
}

bool verifyReturnType(itSymbolItem& it, symbolPtr& smb, iterator first) {
	if (!it->second->get_type_symbol() && !smb->get_type_symbol()) {
        return true;
	}
    if (   (!it->second->get_type_symbol() && smb->get_type_symbol())
		|| (it->second->get_type_symbol() && !smb->get_type_symbol()) ) {
		return false;
	}
    if(strcmp(it->second->get_type_symbol()->to_str(), smb->get_type_symbol()->to_str())) {  // Is the return value different?
        // Here cnome is more flexible to handle the situation of a typedef of int and a 
        // method returning implicitly int.
        bool cond1 = false;
        if (    (cond1 = (*it->second->get_type_symbol() == T_INT && smb->get_type_symbol()->get_identifier_type() == symbol::T_TYPEDEF_NAME))
             || (*smb->get_type_symbol() == T_INT && it->second->get_type_symbol()->get_identifier_type() == symbol::T_TYPEDEF_NAME) )
            // Now, follow typdef definition to see if it is "int"
            for (symbolPtr it2 = cond1?smb->get_type_symbol():it->second->get_type_symbol();it2; it2 = it2->get_type_symbol())
                if (*it2==T_INT)
                    return true;
             
#ifdef _DEBUG
	const char* pc1 = it->second->get_type_symbol()?it->second->get_type_symbol()->to_str():0;
        const char* pc2 = smb->to_str();
#endif	
        static string msg = "";
        msg = msg + "Method '"+smb->to_str()+"' returning a different type from previous declaration.";

        std::cerr << std::endl << msg<< std::endl;
        std::cerr << (it->second->get_symbol_type()==symbol::member?"member": 
                     (it->second->get_symbol_type()==symbol::method)?"method":"other")
                  <<", "
                  << (it->second->get_symbol_status()==symbol::declared?"declared":
                     (it->second->get_symbol_status()==symbol::defined?"defined":"unknown"))
                  << std::endl;
        std::cerr 
                  << first->get_position().get_file() << "(" 
                  << first->get_position().get_line() << ','
                  << first->get_position().get_column() <<")"
                  << std::endl;

        boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
            
    }
    return true;
}

bool operator!=(const symbol& a, const symbol& b) {
#if defined(CNOME_DEBUG)
    std::cerr << "bool operator!=(const symbol& a, const symbol& b)" << std::endl
              << "     a: " << a.to_str() << std::endl
              << "     b: " << b.to_str() << std::endl
              << "     static_cast<token_id>(a) != static_cast<token_id>(b) => " << (static_cast<token_id>(a) != static_cast<token_id>(b)) << std::endl
              << "     strcmp(a.to_str(),b.to_str()) => " << strcmp(a.to_str(),b.to_str()) << std::endl
              << "     a.get_identifier_type() != b.get_identifier_type() => " << (a.get_identifier_type() != b.get_identifier_type()) << std::endl;
#endif
    return     static_cast<token_id>(a) != static_cast<token_id>(b)
            || strcmp(a.to_str(),b.to_str())
            || a.get_identifier_type() != b.get_identifier_type();
}

symbolPtr const typeFinal(symbolPtr const& sIP) {
    symbolPtr sIPAux;
    for (sIPAux = sIP->get_type_symbol() ? sIP->get_type_symbol() : sIP; 
        sIPAux && 
        sIPAux->get_symbol_type() == symbol::typedefname; 
        sIPAux = sIPAux->get_type_symbol());
    
    return sIPAux;
}

bool compareTypes(symbolPtr const& a, symbolPtr const& b) {
    symbolPtr const aFinal(typeFinal(a));
    symbolPtr const bFinal(typeFinal(b));

    return    aFinal != bFinal // Compare parameter type 
           && *aFinal != *bFinal;
}

bool compareParameters(itSymbolItem& it, symbolPtr& smb, iterator first) {
    if (var::prms.size()) {  // Has the method parameters?
        int pos = 0;
        constItPrms its;
        symbol::it_innersT oldItv;
        for (its=var::prms.begin(), oldItv = it->second->get_inners().begin();
            its!=var::prms.end() && oldItv!=it->second->get_inners().end();
            ++its, ++oldItv, ++pos) {
            symbolPtr sybItv = dynamic_cast<parameter_annotation*>(its->second.get_var()->get_annotation().get())->get_symbol_item_ptr();
#ifdef _DEBUG
            const char* pc1 = (*oldItv)->get_value().c_str();
            const char* pc2 = its->second.get_type()->get_value().c_str();
#endif
            symbolPtr pc3 = *oldItv;
            // Verify parameters
            if (compareTypes(*oldItv, sybItv)) {
                static std::string msg = "Internal Compiler error in newMethod.";

                std::cerr << std::endl << msg<< std::endl
                          << "compareParameters: different type of a parameter from previous declaration of method: " << std::endl
                          << "                   " << smb->to_str() << ". Parameter: " << (*oldItv)->to_str() << " has" << std::endl
                          << "                   a different type from previous one in declaration of method in:" << std::endl
                          << "                   " << (*oldItv)->get_position().get_file() << "(" 
                          << "                   " << (*oldItv)->get_position().get_line() << ','
                          << "                   " << (*oldItv)->get_position().get_column() << ")" << std::endl
                          << "                   from current declaration of method in:" << std::endl
                          << "                   " << its->second.get_type()->get_position().get_file() << "(" 
                          << "                   " << its->second.get_type()->get_position().get_line() << ','
                          << "                   " << its->second.get_type()->get_position().get_column() << ")" << std::endl
                          << "                   Previous type is:" << std::endl
                          << "                   " << (*oldItv)->get_type_symbol()->to_str() << " in " << std::endl
                          << "                   " << (*oldItv)->get_type_symbol()->get_position().get_file() << "(" 
                          << "                   " << (*oldItv)->get_type_symbol()->get_position().get_line() << ','
                          << "                   " << (*oldItv)->get_type_symbol()->get_position().get_column() << ")" << std::endl
                          << "                   Current type is:" << std::endl
                          << "                   " << sybItv->get_type_symbol()->to_str() << " in " << std::endl
                          << "                   " << sybItv->get_type_symbol()->get_position().get_file() << "(" 
                          << "                   " << sybItv->get_type_symbol()->get_position().get_line() << ','
                          << "                   " << sybItv->get_type_symbol()->get_position().get_column() << ")" << std::endl
                          << "                   " << std::endl;

                boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
            }

            if ((*oldItv)->get_adorners() != sybItv->get_adorners()) {  // Compare const, '*', ...
                static std::string msg;
                msg = msg + it->second->to_str() + ": Parameter redefinition different from previos one.";

                std::cerr << std::endl << msg<< std::endl;
                std::cerr 
                          << first->get_position().get_file() << "(" 
                          << first->get_position().get_line() << ','
                          << first->get_position().get_column() <<")"
                          << std::endl;

                boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
            }

            if (sybItv->get_symbol_status() != symbol::defined) {    // After the method has been defined the parameter names don't need to be updated
                sybItv->set_token_id(T_IDENTIFIER);
                sybItv->set_symbol_type(symbol::parameter);
                sybItv->set_scope(cnome_symbols.find(smb->to_str())!=cnome_symbols.end()?cnome_symbols.find(smb->to_str())->second:symbolPtr(static_cast<symbol*>(0)));
                sybItv->set_parameter_position(pos); // TODO (alb): Fix this.
#if defined(CNOME_DEBUG)
                std::cout << "newMethod: Parameter " << pos 
                    << ": change name from " << (*oldItv)->to_str() 
                    << " to " << sybItv->to_str() << '.' << std::endl;
#endif
                cnome_symbols.erase((*oldItv)->to_str());  // Remove old declaration
                cnome_symbols[sybItv->to_str()] = symbolPtr(sybItv);  // Add parameter to symbol table 
                *oldItv = cnome_symbols[sybItv->to_str()];                   // to method symbol
            }
        }

        if (its!=var::prms.end() && its->second.get_var() && oldItv==it->second->get_inners().end()) {
            static std::string msg = "Internal Compiler error in newMethod.";

            std::cerr << std::endl << msg<< std::endl;
            std::cerr << "compareParameters: differency between var::prmVars and old parameters" << std::endl;
            std::cerr 
                      << first->get_position().get_file() << "(" 
                      << first->get_position().get_line() << ','
                      << first->get_position().get_column() <<")"
                      << std::endl;

            boost::spirit::classic::throw_(first, static_cast<const char*>(msg.c_str()));
        }
        var::prms.clearVars();  // Now clear all parameters
    }
    return true;
}

void adjustTmplPrms(iterator first, iterator last) {
if (var::tmplSbl)
    for (scopeT::const_iterator it = var::tmplSbl->get_inners().begin(); it != var::tmplSbl->get_inners().end(); it++) {
        cnome_symbols.erase((*it)->to_str());
        (*it)->set_scope(var::tmplSbl);
        cnome_symbols[(*it)->to_str()] = *it;
    }
var::tmplPrms.clear();
}

void newPrm(const std::string& strTypeDecl) {
    if (sglLookahead::instance()->get_is_looking()) {
#if defined(CNOME_DEBUG)
    std::cout << "newPrm: Called inside look_ahead operation" 
        << std::endl;
#endif
        return;  // Do nothing during a lookahead
    }


    itSymbolItem psmb(cnome_symbols.end());
    scopesFromStr scopes(strTypeDecl);
    while (scopes.next_scope().size()) {
        itSymbolItem it;
        if ((it =cnome_symbols.find(scopes.current_scope())) != cnome_symbols.end()) {
            psmb = it;
#if defined(CNOME_DEBUG)
            std::cout << "parameter Type: scopes.current_scope() = " << scopes.current_scope() << endl;
            std::cout << "newPrm: strTypeDecl = " << strTypeDecl << endl;
#endif
        }    
    }

    if (psmb != cnome_symbols.end()) 
        var::prms.add_parameter(*psmb->second);

#if defined(CNOME_DEBUG)
    std::cout << "newPrm: Current Parameters:" << strTypeDecl << endl;
    for (constItPrms it = var::prms.begin(); it != var::prms.end(); it++) {
        if (it->second.get_type()->get_annotation()) {
            if (var::prms.get_level(it) != var::prms.get_level()) {
                break;
            }
        }
        symbolPtr sybIt(dynamic_cast<parameter_annotation*>(it->second.get_type()->get_annotation().get())->get_symbol_item_ptr());
        std::cout << sybIt->to_str() << " : " 
                  << (sybIt->get_type_symbol()?sybIt->get_type_symbol()->to_str():"");
        if (it->second.get_type()->get_annotation()) {
            std::cout << ", level : " << it->first.get_level();
        }
        std::cout << endl;
    }
#endif
}

void handle_typdef_struct_X_X(itSymbolItem& it) {
if (var::typeDecl.size() < 2)
    CLASS_NAME_HELPER=EPSILON;
else {
    scopeT::const_iterator itt = var::typeDecl.begin();
    if (**itt == T_TYPEDEF && **(++itt) == T_IDENTIFIER) {
        isSpecialToken=NOTHING;
        isNotSpecialToken=EPSILON;
    }
    else
        CLASS_NAME_HELPER=EPSILON;
}
}

void handleTypeDefSymbol(itSymbolItem& it) {
itSymbolItem lIt = it;
while (    lIt != cnome_symbols.end() && *(lIt->second) == T_IDENTIFIER 
        && lIt->second->get_symbol_type() == symbol::typedefname && lIt->second->get_type_symbol()
        && !(    (var::typeDecl.size() && *var::typeDecl.front() == T_TYPEDEF)
              || (var::dcl_spc.size() && *var::dcl_spc.front() == T_TYPEDEF)
            )
      ) {
    lIt = cnome_symbols.find(lIt->second->get_type_symbol()->to_str());
#if defined(CNOME_DEBUG)
    if (it != cnome_symbols.end())
        std::cout << "handleTypeDefSymbol: convert previous typedef to : " << it->second->to_str() << endl;
#endif
}
if (lIt == cnome_symbols.end() || lIt->second->get_symbol_type() != symbol::point_to_function)
    it = lIt;
}
  
// TODO (alb): Analyze the code of the following method
// 04oct2010
lvlConstItPrms findInTmplPrms(const char* val_str) {
    // Try match using tmplPrms
#if defined(CNOME_DEBUG)
    std::cout << "findInTmplPrms: val_str = " << val_str << endl;
    std::cout << "findInTmplPrms: var::tmplPrms.size() = " << var::tmplPrms.size() << endl;
    std::cout << "var::tmplPrms.get_level() = " << var::tmplPrms.get_level() << endl;
#endif
    for (int level = var::tmplPrms.get_level(); level >= 0; --level) {
#if defined(CNOME_DEBUG)
        std::cout << "findInTmplPrms: level = " << level << endl;
#endif
        for (lvlConstItPrms its = var::tmplPrms.begin(level); its != var::tmplPrms.end(level); ++its) {
#if defined(CNOME_DEBUG)
            std::cout << "findInTmplPrms: its->second.get_type()->get_value() = " << its->second.get_type()->get_value() << endl;
#endif
            if (its->second.get_type()->get_value() == val_str) {
                return its;
            }
        }
    }

    return var::tmplPrms.end(0);
}
}} // namespace cnome { namespace util {
